#include "wl_ext_os.h"
#include "wl_malloc.h"
#include "wl_list.h"
#include "wl_timer.h"
#include "wl_timer_inner.h"
#include "wl_trace.h"
#include "wl_utils.h"

#define WL_TIMER_NAME_LEN 40

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

typedef struct __wl_timer_message {
    wl_uint32 timer;
} wl_timer_message;

typedef struct {
    wl_uint32     timerid;
    wl_int32      taskid;
    WL_TIMER_TYPE type;
    wl_uint32     interval;
    wl_int32      lifecycle;  //生命期 小于等于0响应
    wl_char       name[WL_TIMER_NAME_LEN];
    wl_ext_timer  timer;
    wl_timer_callback callback;
    void*             context;
} wl_timer_info;

typedef struct {
    wl_bool       initialized;
    wl_list       timer_list;
    wl_ext_mutex  mutex;
    wl_bool       exit;
    wl_uint32     current_timerid;
    wl_ext_queue  msg_queue;
    wl_ext_task   task;
} wl_timer_global;

/*-------------------------------------------------------------------------
模块内部全局变量
-------------------------------------------------------------------------*/
static wl_timer_global s_timer_global;


void timer_callback(wl_ext_timer timer, void *pArg) {
    WLLOGW("initialized %d exit:%d", s_timer_global.initialized, s_timer_global.exit);
    if (s_timer_global.initialized && !s_timer_global.exit) {
        WLLOGW("timer_callback timerid:%d", *((wl_int32*)pArg));
        wl_ext_queue_put(s_timer_global.msg_queue, pArg);
    }
}

void timer_main_thread(wl_ext_task task, void* pArg) {
    wl_int32 timerid;
    void *msg;
    wl_list_iterator iterator;
    wl_timer_info* timer_info = wl_null;
    wl_task_message message;
    wl_timer_message timer_message;

    while (!s_timer_global.exit) {
        if (0
            == wl_ext_queue_get(s_timer_global.msg_queue, &msg)) {
            timerid = *((wl_int32*)msg);
            WLLOGW("timer %d signal", timerid);
            wl_ext_mutex_lock(s_timer_global.mutex, WL_EXT_WAIT_FOREVER);
            timer_info = (wl_timer_info*)wl_list_get_first(&s_timer_global.timer_list, &iterator);
            while (!wl_list_iterator_is_end(&iterator)) {
                if (timerid == timer_info->timerid) {
                    if (REPETITIVE == timer_info->type) {
                        timer_info->lifecycle = timer_info->interval;
                    } else {
                        timer_info->lifecycle = 0;
                    }
                    WLLOGW("timer %d name %s interval %d", timerid, timer_info->name, timer_info->interval);
                    memset(&message, 0, sizeof(wl_task_message));
                    timer_message.timer = timer_info->timerid;
                    message.type = WL_TASK_MSG_TIMER;
                    memcpy(&message.data, &timer_message, sizeof(wl_timer_message));
                    message.datalen = sizeof(wl_timer_message);
                    wl_send_task_message(timer_info->taskid, &message);
                    WLLOGW("send timer message %d", timerid);
                    break;
                }
                timer_info = (wl_timer_info*)wl_list_get_next(&iterator);
            }
            wl_ext_mutex_unlock(s_timer_global.mutex);
        }
        WLLOGT("timer %d signal", timerid);

        //定时器不存在
        if (wl_null == timer_info) {
            WLLOGW("timer %d not exist", timerid);
        }
    }
}


wl_int32 wl_timer_init(void) {
    int ret = -1;
    WLLOGI("wl_timer_init");
    if (!s_timer_global.initialized) {
        ret = wl_ext_mutex_create(&s_timer_global.mutex, "wlsdk_timer");
        if (0 != ret) {
            WLLOGW("wl_mutex_create fail");
            return -1;
        }
        wl_list_init(&s_timer_global.timer_list);
        s_timer_global.exit = wl_false;

        ret = wl_ext_queue_create(&s_timer_global.msg_queue, "wlsdk_timer", 200, "wl_timer");
        if (0 != ret) {
            wl_ext_mutex_destroy(s_timer_global.mutex);
            WLLOGW("wl_queue_create fail");
            return -1;
        }

        //ret = wl_ext_task_create(&s_timer_global.task, "wl_timer", 2*1024, EXT_TASK_PRIORITY_NORMAL, 32, timer_main_thread, wl_null);
        ret = wl_ext_task_static_create(&s_timer_global.task, "wl_timer", timer_main_thread, wl_null);
        if (0 != ret) {
            wl_ext_mutex_destroy(s_timer_global.mutex);
            WLLOGW("pthread_create fail");
            return -1;
        }

        s_timer_global.current_timerid = WL_INVALID_TIMER;
        s_timer_global.initialized     = wl_true;
    }
    return 0;
}

void wl_timer_end(void) {
    wl_list_iterator iterator;
    wl_timer_info* timer_info = wl_null;
    if (s_timer_global.initialized) {
        s_timer_global.exit = wl_true;

        
        timer_info = (wl_timer_info*)wl_list_get_first(&s_timer_global.timer_list, &iterator);
        while (!wl_list_iterator_is_end(&iterator)) {
            wl_ext_timer_stop(timer_info->timer);
            wl_ext_timer_destroy(timer_info->timer);
            timer_info = (wl_timer_info*)wl_list_get_next(&iterator);
        }

        // wl_ext_task_join(s_timer_global.task);
        // wl_ext_task_destroy(s_timer_global.task);
        wl_ext_task_static_destroy(s_timer_global.task);
        s_timer_global.task = 0;

        wl_ext_mutex_lock(s_timer_global.mutex, WL_EXT_WAIT_FOREVER);
        wl_list_free(&s_timer_global.timer_list);
        wl_ext_mutex_unlock(s_timer_global.mutex);
        wl_ext_mutex_destroy(&s_timer_global.mutex);
        wl_ext_queue_destroy(s_timer_global.msg_queue);

        s_timer_global.initialized = wl_false;
    }
}

wl_int32 wl_timer_process_message(wl_task_message* message) {
    wl_timer_message  timer_message;
    wl_list_iterator  iterator;
    wl_timer_info*    timer_info = wl_null;
    wl_timer_callback callback   = wl_null;
    void*             context    = wl_null;
    if (wl_null == message || sizeof(wl_timer_message) != message->datalen) {
        WLLOGW("message is null");
        return -1;
    }
    memcpy(&timer_message, &(message->data), message->datalen);

    WLLOGW("entry wl_timer_process_message timer %d", timer_message.timer);
    wl_ext_mutex_lock(s_timer_global.mutex, WL_EXT_WAIT_FOREVER);
    timer_info = (wl_timer_info*)wl_list_get_first(&s_timer_global.timer_list, &iterator);
    while (!wl_list_iterator_is_end(&iterator)) {
        if (timer_message.timer == timer_info->timerid) {
            callback = timer_info->callback;
            context  = timer_info->context;
            //定时器释放
            WLLOGW("timer %d name %s lifecycle %d", timer_info->timerid, timer_info->name, timer_info->lifecycle);
            if (0 >= timer_info->lifecycle) {
                wl_ext_timer_stop(timer_info->timer);
                wl_ext_timer_destroy(timer_info->timer);
                wl_free(timer_info);
                wl_list_iterator_remove(&iterator);
            }
            break;
        }
        timer_info = (wl_timer_info*)wl_list_get_next(&iterator);
    }

    wl_ext_mutex_unlock(s_timer_global.mutex);

    if (callback) {
        WLLOGW("timer %d callback", timer_message.timer);
        callback(timer_message.timer, context);
    }
    return 0;
}

wl_uint32 wl_timer_create_timerid(void) {
    wl_uint32 timerid = WL_INVALID_TIMER;  // 0表示无效
    while (wl_true) {
        wl_list_iterator iterator;
        wl_timer_info*   timer_info = (wl_timer_info*)wl_list_get_first(&s_timer_global.timer_list, &iterator);
        timerid                     = ++s_timer_global.current_timerid;
        while (!wl_list_iterator_is_end(&iterator)) {
            // timerid已使用或为0
            if (WL_INVALID_TIMER == s_timer_global.current_timerid
                || s_timer_global.current_timerid == timer_info->timerid) {
                timerid = WL_INVALID_TIMER;
                break;
            }
            timer_info = (wl_timer_info*)wl_list_get_next(&iterator);
        }
        if (WL_INVALID_TIMER != timerid) {
            break;
        }
    }
    return timerid;
}

WL_TIMER
wl_timer_start(wl_uint32         interval,
               WL_TIMER_TYPE     type,
               wl_timer_callback callback,
               void*             context,
               wl_int32          taskid,
               wl_char*          timer_name) {
    wl_timer_info* timer_info;

    wl_ext_mutex_lock(s_timer_global.mutex, WL_EXT_WAIT_FOREVER);
    timer_info = (wl_timer_info*)wl_malloc(sizeof(wl_timer_info));
    if (wl_null != timer_info) {
        memset(timer_info, 0, sizeof(wl_timer_info));
        timer_info->timerid   = wl_timer_create_timerid();
        timer_info->taskid    = taskid;
        timer_info->type      = type;
        timer_info->interval  = interval;
        timer_info->lifecycle = interval;
        timer_info->callback  = callback;
        timer_info->context   = context;
        if (timer_name) {
            strncpy(timer_info->name, timer_name, sizeof(timer_info->name) - 1);
            timer_info->name[sizeof(timer_info->name) - 1] = '\0';
        }
        WLLOGW("wl_timer_start timer %s", timer_info->name);

        if (0 != wl_ext_timer_create(&timer_info->timer, timer_info->name)) {
            WLLOGW("wl_ext_timer_create fail");
            wl_free(timer_info);
            wl_ext_mutex_unlock(s_timer_global.mutex);
            return WL_INVALID_TIMER;
        }

        WLLOGW("timer_info->timerid=%d", timer_info->timerid);
        if (0 != wl_ext_timer_start(timer_info->timer, NON_REPETITIVE == type ? 0 : 1, interval, timer_callback, &timer_info->timerid)) {
            wl_ext_timer_destroy(timer_info->timer);
            WLLOGW("ql_rtos_timer_start fail");
            wl_free(timer_info);
            wl_ext_mutex_unlock(s_timer_global.mutex);
            return WL_INVALID_TIMER;
        }

        if (-1 == wl_list_add(&s_timer_global.timer_list, timer_info, -1)) {
            WLLOGW("wl_list_add fail");
            wl_ext_timer_stop(timer_info->timer);
            wl_ext_timer_destroy(timer_info->timer);
            wl_free(timer_info);
            wl_ext_mutex_unlock(s_timer_global.mutex);
            return WL_INVALID_TIMER;
        }
        WLLOGW("wl_timer_start timer count %d", wl_list_size(&s_timer_global.timer_list));
    }

    wl_ext_mutex_unlock(s_timer_global.mutex);

    WLLOGT("wl_timer_start success");
    return timer_info->timerid;
}

wl_int32 wl_timer_stop(WL_TIMER timer) {
    wl_timer_info*   timer_info;
    wl_list_iterator iterator;

    wl_ext_mutex_lock(s_timer_global.mutex, WL_EXT_WAIT_FOREVER);
    timer_info = (wl_timer_info*)wl_list_get_first(&s_timer_global.timer_list, &iterator);
    while (!wl_list_iterator_is_end(&iterator)) {
        if (timer == timer_info->timerid) {
            WLLOGW("wl_timer_stop timer %d", timer);
            wl_ext_timer_stop(timer_info->timer);
            wl_ext_timer_destroy(timer_info->timer);
            wl_free(timer_info);
            wl_list_iterator_remove(&iterator);
            break;
        }
        timer_info = (wl_timer_info*)wl_list_get_next(&iterator);
    }
    WLLOGW("wl_timer_stop timer count %d", wl_list_size(&s_timer_global.timer_list));
    wl_ext_mutex_unlock(s_timer_global.mutex);
    WLLOGW("wl_timer_stop end");
    return 0;
}

#ifdef __cplusplus
}
#endif /* __cplusplus */
